/*
 * ValueObj.cpp
 *
 *  Created on: 03/01/2011
 *      Author: wlad
 */

#include "ValueObj.h"
#include <string.h>
#include <stdlib.h>

ValueObj::ValueObj() {
	m_tipo = nulo;
	init(NULL);
}

ValueObj::~ValueObj() {
	m_nome.clear();
	freeData();
}

ValueObj::ValueObj(ValueObj & obj, const char *nome) {
	init(nome);
	*this = obj;
}

ValueObj::ValueObj(const char *s, const char *nome) {
	init(nome);
	*this = s;
}

ValueObj::ValueObj(int i, const char *nome) {
	init(nome);
	*this = i;
}

ValueObj::ValueObj(float d, const char *nome) {
	init(nome);//
	*this = nome;
}

string ValueObj::operator =(const char *v) {

	if (m_tipo != caracter) {
		freeData();
		m_data.caracter = new string();
		this->m_tipo = caracter;
	}

	m_data.caracter->assign(v);
	return *m_data.caracter;
}

int ValueObj::operator =(int v) {
	if ((m_tipo == caracter) || (m_tipo == array)) {
		freeData();
	}
	m_tipo = inteiro;
	m_data.inteiro = v;
	return v;
}

float ValueObj::operator =(float v) {
	if ((m_tipo == caracter) || (m_tipo == array)) {
		freeData();
	}
	m_tipo = decimal;
	m_data.decimal = v;
	return v;
}

ValueObj::operator int() const {

	if (m_tipo == inteiro)
		return m_data.inteiro;

	else if (m_tipo == decimal)
		return (int) m_data.decimal;

	else if (m_tipo == caracter) {
		return atoi(m_data.caracter->c_str());
	}

	return 0;
}

ValueObj::operator float() const {
	if (m_tipo == inteiro)
		return (int) m_data.inteiro;

	else if (m_tipo == decimal)
		return m_data.decimal;

	else if (m_tipo == caracter) {
		return atof(m_data.caracter->c_str());
	}

	return 0;
}

ValueObj::operator string() const {
	stringstream ss;

	if (m_tipo == inteiro)
		ss << m_data.inteiro;

	else if (m_tipo == decimal)
		ss << m_data.decimal;

	else if (m_tipo == caracter) {
		return *m_data.caracter;
	} else if (m_tipo == array) {
		ss << "Array " << m_nome << " : ";
		ss << m_data.array.length;
	}

	return ss.str();
}

ValueObj & ValueObj::operator [](int index) {

	if (m_tipo != array){
		freeData();
		m_tipo = array;
	}


	if (index >= m_data.array.length)
		expandTo(index+1);

	if (!m_data.array.itens[index])
		m_data.array.itens[index] = new ValueObj();

	return *m_data.array.itens[index];

}

ValueObj & ValueObj::operator [](const char *nome) {
	return *find(nome);
}

void ValueObj::init(const char *nome) {
	m_tipo = nulo;

	freeData();

	if (nome) {
		m_nome = nome;
	} else {
		stringstream ss;
		static int i = 0;
		ss << i++;

		m_nome.clear();
		m_nome.append("sem_nome_");
		m_nome.append(ss.str());

	}

}

void ValueObj::freeData() {
	if (m_tipo == caracter)
		delete m_data.caracter;

	if ((m_tipo == array) && (m_data.array.itens)) {
		for (int i = 0; i < m_data.array.length; i++)
			if (m_data.array.itens[i])
				delete m_data.array.itens[i];
		delete[] m_data.array.itens;
	}

	memset(&m_data, 0, sizeof(m_data));
}

ValueObj *ValueObj::find(const char *nome) {
	///TODO:Implementar a busca binaria
	pValueObj p;
	for (int i = 0; i < m_data.array.length; i++)
		if ((p = m_data.array.itens[i]) && (m_data.array.itens[i]->getNome()
				== string(nome)))
			return p;

	throw ValueObjAcessoInvalido(string("Item não encontrado no array : ")
			+ string(nome));
}

int ValueObj::getTipo() {
	return m_tipo;
}

string ValueObj::getNome() {
	return m_nome;
}

void ValueObj::compact(){
///TODO : implementar o metodo compact
}

void ValueObj::expandTo(int new_length) {
	if (m_tipo != array) {
		freeData();
		m_tipo = array;
	}

	int new_size = (new_length / VALUE_OBJ_EXPAND_ARRAY_STEP + 1)
			* VALUE_OBJ_EXPAND_ARRAY_STEP;

	pValueObj* temp = NULL;
	if (new_size > m_data.array.size) {
		temp = new pValueObj[new_size];
		memset(temp, 0, m_data.array.length * sizeof(pValueObj));
		if (m_data.array.itens) {
			memcpy(temp, m_data.array.itens, m_data.array.length
					* sizeof(pValueObj));
			delete[] m_data.array.itens;
		}
		m_data.array.itens = temp;
		m_data.array.size = new_size;
	}

	limpaArray(new_length - 1, m_data.array.length - 1);
	m_data.array.length = new_length;

}

void ValueObj::limpaArray(int inicio, int fim) {
	if (m_tipo != array)
		return;
	if (m_data.array.itens)
		for (int c = inicio; c <= fim; c++)
			if (m_data.array.itens[c]) {
				delete m_data.array.itens[c];
				m_data.array.itens[c] = NULL;
			}

}

void ValueObj::dump() {
	cout << "variavel : " << m_nome << " : ";

	if (m_tipo == inteiro)
		cout << " (inteiro) : " << m_data.inteiro;
	else if (m_tipo == decimal)
		cout << " (decimal) : " << m_data.decimal;
	else if (m_tipo == caracter)
		cout << " (caracter) : " << *m_data.caracter;
	else if (m_tipo == nulo)
		cout << "(nulo)";
	else if (m_tipo == array) {
		cout << "(Array) : ";
		cout << m_data.array.length;
	}
	cout << endl << endl;

}

ValueObj & ValueObj::add(ValueObj *obj) {
	expandTo(m_data.array.length);
	if (m_data.array.itens[m_data.array.length])
		delete m_data.array.itens[m_data.array.length];

	return *(m_data.array.itens[m_data.array.length++] = obj);

}

int ValueObj::getLength() {
	return m_tipo == array ? m_data.array.length : -1;
}
